use std::net::SocketAddr;

use crate::{
  app::{
    auth::{Principal, get_jwt},
    error::ApiError,
    response::ApiResponse,
    utils::verify_password,
  },
  entity::{company, prelude::*},
};
use axum::{
  Extension, Router, debug_handler,
  extract::{ConnectInfo, State},
  routing::{get, post},
};
use sea_orm::prelude::*;
use serde::{Deserialize, Serialize};
use validator::Validate;

use crate::app::{AppState, middleware::get_auth_layer, yvalid};

use super::user::ApiResultResponse;

pub fn create_router() -> Router<AppState> {
  Router::new()
    .route("/user_info", get(get_user_info))
    .route_layer(get_auth_layer())
    .route("/login", post(login)) // 不需要鉴权
}

#[derive(Debug, Deserialize, Validate)]
pub struct LoginParams {
  #[validate(length(min = 3, max = 16, message = "账号长度为3-16"))]
  account: String,
  #[validate(length(min = 6, max = 16, message = "密码长度为6-16"))]
  password: String,
}

#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")] // 小写驼峰返回
pub struct LoginResult {
  access_token: String,
}

/// curl http://127.0.0.1:3000/api/auth/login -X POST -H "Content-Type: application/json" -d '{"account": "admin", "password":"15764336340"}'
// #[tracing::instrument(name="login", skip_all, fields(account=tracing::field::Empty))]
#[debug_handler]
#[tracing::instrument(name = "login", skip_all, fields(account = %params.account, ip = %addr.ip()))]
async fn login(
  State(AppState { db }): State<AppState>,
  ConnectInfo(addr): ConnectInfo<SocketAddr>,
  yvalid::ValidJson(params): yvalid::ValidJson<LoginParams>,
) -> ApiResultResponse<LoginResult> {
  tracing::info!("{:?} 正在登陆...", addr.ip());
  let user = Company::find()
    .filter(company::Column::Name.eq(&params.account))
    .one(&db)
    .await?
    .ok_or_else(|| ApiError::Biz("账号或密码不正确".to_string()))?;

  if !verify_password(&params.password, &user.address.expect("用户密码不存在"))?
  {
    return Err(ApiError::Biz("账号或密码不正确".to_string()));
  }

  let principal = Principal {
    id: user.id,
    name: user.name,
  };
  let access_token = get_jwt().encode(principal)?;
  tracing::info!("登陆成功, JWT Token: {access_token}");
  Ok(ApiResponse::ok("ok", Some(LoginResult { access_token })))
}

/// curl http://127.0.0.1:3000/api/auth/user_info -X GET -H "Authorization: Bearer xxxxxxxx"
#[debug_handler]
async fn get_user_info(
  // State(AppState { db }): State<AppState>,
  Extension(principal): Extension<Principal>,
) -> ApiResultResponse<Principal> {
  Ok(ApiResponse::ok("ok", Some(principal)))
}
